package com.jwds.digital.bios.business.service.service.belt.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jwds.digital.bios.business.core.exceptions.RecordNotFoundException;
import com.jwds.digital.bios.business.core.infrastructure.dto.belt.BeltRouteTaskMainReqDTO;
import com.jwds.digital.bios.business.core.infrastructure.dto.belt.assembler.BeltRouteTaskMainAssembler;
import com.jwds.digital.bios.business.core.infrastructure.entity.belt.BeltRouteTaskMain;
import com.jwds.digital.bios.business.core.infrastructure.mapper.belt.BeltRouteTaskMainMapper;
import com.jwds.digital.bios.business.core.infrastructure.vo.belt.BeltRouteTargetHisRespVO;
import com.jwds.digital.bios.business.core.infrastructure.vo.belt.BeltRouteTaskMainRespVO;
import com.jwds.digital.bios.business.core.infrastructure.vo.belt.LineDataRespVo;
import com.jwds.digital.bios.business.core.infrastructure.vo.belt.tonPowerConsumptionRespVO;
import com.jwds.digital.bios.business.service.service.belt.IBeltRouteTaskMainService;
import com.jwds.tdc.framework.application.lib.page.PageRequest;
import com.jwds.tdc.framework.application.lib.page.PageResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 路线作业实绩主表实现类
 * @author 林柏云
 * @date 2024-11-28
 */
@Slf4j
@Service
public class BeltRouteTaskMainServiceImpl extends ServiceImpl<BeltRouteTaskMainMapper, BeltRouteTaskMain> implements IBeltRouteTaskMainService {

  @Autowired
  private BeltRouteTaskMainMapper baseMapper;

  @Override
  public BeltRouteTaskMainRespVO queryById(Long id) {
    if(id == null) {
      return null;
    }
    BeltRouteTaskMain entity = baseMapper.selectById(id);
    return BeltRouteTaskMainAssembler.entity2dto(entity);
  }

  @Override
  public PageResponse<BeltRouteTaskMainRespVO> page(PageRequest<BeltRouteTaskMainReqDTO> request) {
    BeltRouteTaskMainReqDTO condition = request.getQueryCondition();
    Page<BeltRouteTaskMainRespVO> page = new Page<>(request.getPageIndex(), request.getPageSize());
    IPage<BeltRouteTaskMainRespVO> pageData = baseMapper.pageQuery(page, condition);
    return new PageResponse<>((Page<?>)pageData, pageData.getRecords());
  }

  @Override
  public List<BeltRouteTaskMainRespVO> list(BeltRouteTaskMainReqDTO reqDto) {
    return baseMapper.queryList(reqDto);
  }

  @Override
  public void add(BeltRouteTaskMainReqDTO reqDto) {
    BeltRouteTaskMain entity = BeltRouteTaskMainAssembler.dto2entity(reqDto);
    baseMapper.insert(entity);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void batchAdd(List<BeltRouteTaskMainReqDTO> dtoList) {
    dtoList.forEach(this::add);
  }

  @Override
  public void update(BeltRouteTaskMainReqDTO reqDto) {
    BeltRouteTaskMain oldEntity = baseMapper.selectById(reqDto.getId());
    if (oldEntity == null) {
      throw new RecordNotFoundException();
    }
    BeltRouteTaskMain newEntity = BeltRouteTaskMainAssembler.dto2entity(reqDto, oldEntity);
    baseMapper.updateById(newEntity);
  }

  @Override
  public void delete(Long id) {
    BeltRouteTaskMain oldEntity = baseMapper.selectById(id);
    if (oldEntity == null) {
      throw new RecordNotFoundException();
    }
    baseMapper.deleteById(id);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void batchDelete(List<Long> ids) {
    for (Long id : ids) {
      delete(id);
    }
  }

  @Override
  public List<BeltRouteTaskMainRespVO> getExecutiveJobInformation() {

    // 当前正在执行的作业信息
    List<BeltRouteTaskMainRespVO> executiveJobInformation = baseMapper.getExecutiveJobInformation(DateUtil.beginOfDay(new Date()));

    return executiveJobInformation;

  }

  @Override
  public BeltRouteTaskMainRespVO lineDataMessage(Long routeId) {

    // 线路基础信息
    BeltRouteTaskMainRespVO beltRouteTaskMainRespVO = baseMapper.lineDataMessage(DateUtil.beginOfDay(new Date()), routeId);

    if (!Objects.isNull(beltRouteTaskMainRespVO)) {

      // 获取线路历史信息
      BeltRouteTargetHisRespVO beltRouteTargetHisRespVO = baseMapper.lineHistoryInformation(beltRouteTaskMainRespVO.getFlowNo());

      if (Objects.isNull(beltRouteTargetHisRespVO)) {
        return beltRouteTaskMainRespVO;
      }

      // 新值大于历史值，返回正数； 新值小于历史值，返回负数； 两者相等，返回零。
      // 获取吨料耗电量以及百分比
      Integer tonPower = beltRouteTaskMainRespVO.getAvgTonPowerConsumption().compareTo(beltRouteTargetHisRespVO.getTonPowerConsumption());
      BigDecimal tonPowerConsumptionPercent = calculatePercentageChange(beltRouteTaskMainRespVO.getAvgTonPowerConsumption(), beltRouteTargetHisRespVO.getTonPowerConsumption());
      beltRouteTaskMainRespVO.setTonPower(tonPower);
      beltRouteTaskMainRespVO.setTonPowerConsumptionPercent(tonPowerConsumptionPercent);

      // 获取空载时长占比以及百分比
      Integer unLoadRunning = beltRouteTaskMainRespVO.getUnLoadRunningTime().compareTo(beltRouteTargetHisRespVO.getUnLoadRunningTime());
      BigDecimal unLoadRunningTimePercent = calculatePercentageChange(beltRouteTaskMainRespVO.getUnLoadRunningTime(), beltRouteTargetHisRespVO.getUnLoadRunningTime());
      beltRouteTaskMainRespVO.setUnLoadRunning(unLoadRunning);
      beltRouteTaskMainRespVO.setUnLoadRunningTimePercent(unLoadRunningTimePercent);

      // 获取运行空载时长占比以及百分比
      BigDecimal divide = beltRouteTaskMainRespVO.getRunningNoLoadDuration().divide(beltRouteTaskMainRespVO.getUnLoadRunningTime(), 2);
      Integer runningUnLoad = divide.compareTo(beltRouteTargetHisRespVO.getRunningUnLoadRate());
      BigDecimal runningUnLoadRatePercent = calculatePercentageChange(divide, beltRouteTargetHisRespVO.getRunningUnLoadRate());
      beltRouteTaskMainRespVO.setRunningUnLoad(runningUnLoad);
      beltRouteTaskMainRespVO.setRunningUnLoadRatePercent(runningUnLoadRatePercent);

      // 获取空载能耗占比以及百分比
      Integer unLoadPower = beltRouteTaskMainRespVO.getUnLoadPowerConsumptionRate().compareTo(beltRouteTargetHisRespVO.getUnLoadPowerConsumptionRate());
      BigDecimal unLoadPowerConsumptionRatePercent = calculatePercentageChange(beltRouteTaskMainRespVO.getUnLoadPowerConsumptionRate(), beltRouteTargetHisRespVO.getUnLoadPowerConsumptionRate());
      beltRouteTaskMainRespVO.setUnLoadPower(unLoadPower);
      beltRouteTaskMainRespVO.setUnLoadPowerConsumptionRatePercent(unLoadPowerConsumptionRatePercent);

      beltRouteTaskMainRespVO.setWorkEfficiencyExcellent(beltRouteTargetHisRespVO.getWorkEfficiencyExcellent());
      beltRouteTaskMainRespVO.setWorkEfficiencyGood(calculateAverageEfficiency(beltRouteTargetHisRespVO.getWorkEfficiencyWrong(),beltRouteTargetHisRespVO.getWorkEfficiencyExcellent()));
      beltRouteTaskMainRespVO.setWorkEfficiencyWrong(beltRouteTargetHisRespVO.getWorkEfficiencyWrong());
      beltRouteTaskMainRespVO.setAvgAllLoadRateExcellent(beltRouteTargetHisRespVO.getAvgAllLoadRateExcellent());
      beltRouteTaskMainRespVO.setAvgAllLoadRateGood(calculateAverageEfficiency(beltRouteTargetHisRespVO.getAvgAllLoadRateWrong(),beltRouteTargetHisRespVO.getAvgAllLoadRateExcellent()));
      beltRouteTaskMainRespVO.setAvgAllLoadRateWrong(beltRouteTargetHisRespVO.getAvgAllLoadRateWrong());
      beltRouteTaskMainRespVO.setAvgResistanceExcellent(beltRouteTargetHisRespVO.getAvgResistanceExcellent());
      beltRouteTaskMainRespVO.setAvgResistanceGood(calculateAverageEfficiency(beltRouteTargetHisRespVO.getAvgResistanceWrong(),beltRouteTargetHisRespVO.getAvgResistanceExcellent()));
      beltRouteTaskMainRespVO.setAvgResistanceWrong(beltRouteTargetHisRespVO.getAvgResistanceWrong());
      beltRouteTaskMainRespVO.setTransportEfficiencyExcellent(beltRouteTargetHisRespVO.getTransportEfficiencyExcellent());
      beltRouteTaskMainRespVO.setTransportEfficiencyGood(calculateAverageEfficiency(beltRouteTargetHisRespVO.getTransportEfficiencyWrong(),beltRouteTargetHisRespVO.getTransportEfficiencyExcellent()));
      beltRouteTaskMainRespVO.setTransportEfficiencyWrong(beltRouteTargetHisRespVO.getTransportEfficiencyWrong());
      beltRouteTaskMainRespVO.setEnergyEfficiency("");

      beltRouteTaskMainRespVO.setAvgPowerEvaluation(sheetEvaluation(tonPower));
      beltRouteTaskMainRespVO.setUnloadedTimeEvaluation(sheetEvaluation(unLoadRunning));
      beltRouteTaskMainRespVO.setRunUnloadedEvaluation(sheetEvaluation(runningUnLoad));
      beltRouteTaskMainRespVO.setUnloadedPowerEvaluation(sheetEvaluation(unLoadPower));

      // 线路效率信息
      List<LineDataRespVo> lineDataRespVoList = baseMapper.lineRateData(DateUtil.beginOfDay(new Date()), routeId);

      List<tonPowerConsumptionRespVO> tonPowerConsumptionRespVOList = baseMapper.tonPowerConsumption(DateUtil.beginOfDay(new Date()), routeId);

      beltRouteTaskMainRespVO.setWorkingEfficiencyEvaluation(evaluation(lineDataRespVoList.get(lineDataRespVoList.size() - 1).getWorkingEfficiency(),
              beltRouteTargetHisRespVO.getWorkEfficiencyWrong(),
              beltRouteTargetHisRespVO.getWorkEfficiencyExcellent()));
      beltRouteTaskMainRespVO.setWorkEfficiencyEvaluation(evaluation(lineDataRespVoList.get(lineDataRespVoList.size() - 1).getWorkEfficiency(),
              beltRouteTargetHisRespVO.getTransportEfficiencyWrong(),
              beltRouteTargetHisRespVO.getTransportEfficiencyExcellent()));
      beltRouteTaskMainRespVO.setLoadRatioEvaluation(evaluation(lineDataRespVoList.get(lineDataRespVoList.size() - 1).getLoadRatio(),
              beltRouteTargetHisRespVO.getAvgAllLoadRateWrong(),
              beltRouteTargetHisRespVO.getAvgAllLoadRateExcellent()));
      beltRouteTaskMainRespVO.setTonPowerConsumptionEvaluation(evaluation(tonPowerConsumptionRespVOList.get(tonPowerConsumptionRespVOList.size() - 1).getTonPowerConsumption(),
              beltRouteTargetHisRespVO.getTonPowerConsumptionExcellent(),
              beltRouteTargetHisRespVO.getTonPowerConsumptionWrong()));

      beltRouteTaskMainRespVO.setLineDataRespVoList(lineDataRespVoList);
      beltRouteTaskMainRespVO.setTonPowerConsumptionRespVOList(tonPowerConsumptionRespVOList);
    }

    return beltRouteTaskMainRespVO;
  }

  @Override
  public Integer numberOfUnduplicatedTasks(Short flowNo, LocalDateTime startTime, LocalDateTime endTime) {
    return baseMapper.numberOfUnduplicatedTasks(flowNo, startTime, endTime);
  }

  /**
   * 计算变化百分比
   * @param newValue 新值
   * @param oldValue 旧值
   * @return 变化百分比
   */
  private static BigDecimal calculatePercentageChange(BigDecimal newValue, BigDecimal oldValue) {

    if (oldValue.compareTo(BigDecimal.ZERO) == 0) {
      throw new ArithmeticException("Cannot calculate percentage change when the old value is zero.");
    }

    // 避免除以零的情况
    BigDecimal change = newValue.subtract(oldValue);
    BigDecimal percentageChange = change.divide(oldValue, 2, RoundingMode.HALF_UP);
    return percentageChange;
  }

  /**
   * 获取报表评价
   * @param value 最新值
   * @param passValue 及格值
   * @param excellentValue 优秀值
   * @return 评价
   */
  private static String evaluation(BigDecimal value, BigDecimal passValue, BigDecimal excellentValue) {
    if (value == null || passValue == null || excellentValue == null) {
      throw new IllegalArgumentException("All values must be non-null.");
    }

    if (value.compareTo(passValue) < 0) {
      return "差";
    } else if (value.compareTo(excellentValue) < 0) {
      return "良";
    } else {
      return "优";
    }
  }

  /**
   * 获取表格评价
   * @param value 差值
   * @return 评价
   */
  private static String sheetEvaluation(Integer value) {
    if (value == 0) {
      return "良";
    }

    if (value == -1) {
      return "差";
    }

    return "优";
  }

  /**
   * 计算良对应值
   * @param passValue 及格线
   * @param excellentValue 优秀线
   * @return 评价
   */
  public static BigDecimal calculateAverageEfficiency(BigDecimal passValue,BigDecimal excellentValue) {
    // 相加
    BigDecimal sum = passValue.add(excellentValue);

    // 求平均值，保留两位小数并采用四舍五入的方式
    BigDecimal average = sum.divide(BigDecimal.valueOf(2), 2, RoundingMode.HALF_UP);

    return average;
  }

}
